home *** CD-ROM | disk | FTP | other *** search
/ Graphics Plus / Graphics Plus.iso / msdos / raytrace / dbwrend / source / display.c < prev    next >
Text File  |  1989-11-04  |  19KB  |  664 lines

  1. /************************************************************/
  2. /*                                                          */
  3. /*   changes -                                              */
  4. /*   10/31/89  ver 1.02 - allow for new maxcol and maxrow   */
  5. /*             integers at front of temp file.  They are    */
  6. /*             scanned off & ignored, for now               */
  7. /*                                                          */ 
  8. /************************************************************/
  9.  
  10. #include <stdio.h>
  11. #include <stdlib.h>
  12. #include <fcntl.h>
  13. #include <io.h>
  14. #include <sys\types.h>
  15. #include <sys\stat.h>
  16. #include <graph.h>
  17.  
  18. #include "display.h"
  19.  
  20. #define VERSION "\nDISPLAY v1.02 (IBM MCGA/VGA)\nCopyright (C) 1989 J. Lowery.  All rights reserved.\n\n"
  21.  
  22. struct {
  23.      int       curr;
  24.      int       fp;
  25.        } ifil[10];
  26.  
  27. static int     numfiles = 0;
  28. static int     colorstats[TMPCOLORS][2];
  29. static int     image[MAXCOL];
  30. static char    fname[40],outname[40],str[40];
  31. static int     usedColors;
  32. static int     giffile;
  33.  
  34. /* 'ofil' must be accessable to gif output functions in another module */
  35.        int     ofil;
  36.  
  37. /* buffer for a single scan line */
  38. static scanlinetype line;
  39.  
  40.  
  41.  
  42. /* GIF header mode byte definitions */
  43.  
  44. #define GLOBALCOLORMAP 0x80
  45. #define COLORRES       ((DEPTH-1) << 4)
  46. #define BITSPERPIXEL   (BITS-1)
  47.  
  48. /* 
  49.  *   the following structures are odd lengths and mix byte- and 
  50.  *   word-length objects, so MUST be packed on 1-byte boundaries, 
  51.  *   or file operations break.
  52.  */
  53.  
  54. #pragma pack(1)
  55.  
  56. struct {
  57.      char signature[6];
  58.      int  screenWidth;
  59.      int  screenHeight;
  60.  
  61.      byte mode;
  62.      byte background;
  63.      byte empty;
  64.  
  65.      } gifHeader = { "GIF87a", MAXCOL, MAXROW, 
  66.                      GLOBALCOLORMAP | COLORRES | BITSPERPIXEL, 0, 0 };
  67.  
  68.  
  69. struct {
  70.      char separator;
  71.      int  imageLeft;
  72.      int  imageTop;
  73.      int  imageWidth;
  74.      int  imageHeight;
  75.      byte mode;
  76.      byte codeSize;      /* this is actually part of the image data stream */
  77.  
  78.      } imageHeader = { ',', 0, 0, MAXCOL, MAXROW, BITSPERPIXEL, BITS }; 
  79.  
  80. /* back to normal structure packing */
  81. #pragma pack()
  82.  
  83. /*   
  84.  *   display write error, wait for operator acknowledge, 
  85.  *   reset video & return.  This is used while video is in 320x200
  86.  *   mode. 
  87.  */
  88.  
  89. int writeError()
  90. {
  91.      close( ofil );           /* close the file   */
  92.  
  93.      _settextposition( 16, 0 );
  94.      printf("Write error in file %s\n", outname);
  95.      printf("Press any key to exit...");
  96.      while (!kbhit())
  97.           ;
  98.      getch();
  99.      return( TRUE );
  100. }
  101.  
  102. int gifHdr()      /* create a GIF file from screen */
  103. {
  104.      byte colorValue[3];      /* a single rgb triplet */
  105.      int  i;
  106.  
  107.      /* write the header information */
  108.      if (write(ofil, (char *)&gifHeader, sizeof(gifHeader)) != sizeof(gifHeader))
  109.           return( writeError() );
  110.  
  111.      /* write the global color map   */
  112.      for (i=0; i<COLORS; i++)
  113.      {
  114.           /* 
  115.            *   for each of our 256 possible colors, 
  116.            *   map the color's 3 primary intesities (0..15) into 
  117.            *   the gif color map color intensities (0..255).
  118.            *   Note that i==0 defines the MCGA border color.
  119.            */
  120.  
  121.           if (i < usedColors)
  122.           {
  123.                colorValue[2] = ((long)(colorstats[i][0] & 0x0F00) >> 4); /* blue  */
  124.                colorValue[1] = ((long)(colorstats[i][0] & 0x00F0) );     /* green */
  125.                colorValue[0] = ((long)(colorstats[i][0] & 0x000F) << 4 ); /* red   */
  126.           }
  127.           else
  128.           {
  129.                colorValue[0] = 0;
  130.                colorValue[1] = 0;
  131.                colorValue[2] = 0;
  132.           }
  133.  
  134.           if (write( ofil, colorValue, sizeof(colorValue)) != sizeof(colorValue))
  135.                return( writeError() );
  136.      }
  137.      /* write the image descriptor */
  138.      if (write(ofil, (char *)&imageHeader, sizeof(imageHeader)) != sizeof(imageHeader))
  139.           return( writeError() );
  140.  
  141.      return(0);       /* header complete, return ok */ 
  142. }
  143.  
  144.  
  145. char terminal[2] = { 0, ';' };     /* image terminator sequence */
  146.  
  147. int gifClose()
  148. {
  149.  
  150.      if (gifFlush())
  151.           return(TRUE);
  152.      if (write( ofil, terminal, sizeof( terminal )) != sizeof( terminal ))
  153.           return( writeError() );
  154.  
  155.      close( ofil );
  156.      return(FALSE);      /* no error */     
  157. }
  158.  
  159. /* reset video mode, print error message and exit */
  160.  
  161. void error( msg )
  162. char *msg;
  163. {
  164.      _setvideomode( _DEFAULTMODE );
  165.      printf( "ERROR: %s\n", msg );
  166.      exit( -1 );
  167. }
  168.  
  169. /* print error message and exit.  Used in 80-column text mode */
  170.  
  171. void usageExit( msg )
  172. char *msg;
  173. {
  174.      if (msg) 
  175.           printf("ERROR: %s\n",msg);
  176.  
  177.      printf("\nUsage: raydsp [-g outfile] infile [infile [...]] \n");
  178.      printf("\nWhere: -g       Creates GIF file from screen display");
  179.      printf("\n       outfile  GIF output file name.");
  180.      printf("\n       infile   Input DBW_Render .TMP file.\n");
  181.      printf("\nDisplays a DBW_Render output file, and optionally ");
  182.      printf("\nconverts it to Compuserve (tm) GIF format.\n\n");
  183.      exit(-1);
  184. }
  185.  
  186. read_scanline(pass,row)
  187. int pass,row;
  188. {
  189.      int i,j,x,val,good;
  190.  
  191.      if (pass < 2)
  192.      {    if ((row % 50) == 0) 
  193.                printf("\nRow: %4d ",row);
  194.           printf(".");
  195.           fflush(stdout);
  196.      }
  197.  
  198.      good = 0;
  199.      for (i = 0; i < numfiles && good == 0; i++) 
  200.      {
  201.           while (ifil[i].curr < row) 
  202.           {
  203.                if (read(ifil[i].fp,(char *)&ifil[i].curr,sizeof(int))!=sizeof(int)) 
  204.                {
  205.                     ifil[i].curr = 9999; 
  206.                     continue;
  207.                }
  208.  
  209.                if (read(ifil[i].fp,(char *)line,sizeof(scanlinetype))!=sizeof(scanlinetype))
  210.                {
  211.                     ifil[i].curr = 9999;
  212.                     continue;
  213.                }
  214.                if (ifil[i].curr == row) 
  215.                {
  216.                     good = 1;
  217.                     break;
  218.                }
  219.           }
  220.      }
  221.  
  222.     /* couldn't find this scan line in any file */
  223.  
  224.      if (good == 0) 
  225.           return(0);
  226.  
  227.      x = 0;
  228.      for (i = 0; i < WPSL; i++) 
  229.      {
  230.           for (j = 0; j < PPW; j++) 
  231.           {
  232.           /*--- TMP file has red, green, then blue nibbles.  Palette
  233.                 needs them as blue (MSB), green, red (LSB) ----------*/
  234.  
  235.                val = (  ((line[RED  ][i] >> (BPP * j)) & (MAXGRAY-1))               /* red   */
  236.                      + (((line[GREEN][i] >> (BPP * j)) & (MAXGRAY-1)) <<  BPP)      /* green */
  237.                      + (((line[BLUE ][i] >> (BPP * j)) & (MAXGRAY-1)) << (BPP*2))); /* blue  */
  238.  
  239.                val %= TMPCOLORS;
  240.  
  241.                if (pass == 1)      /* histogram count on pass 1 */
  242.                {
  243.                     if (colorstats[val][1] < 32767) 
  244.                          colorstats[val][1]++;
  245.                }
  246.                else 
  247.                     image[x++] = val;
  248.           }
  249.      }
  250.      return(1);
  251. }
  252.  
  253. /* 
  254.  *   find the darkest color in colorstats[], and make it
  255.  *   colorstats[0], for use as a border color
  256.  */
  257.  
  258. getBackground()
  259. {
  260.      /* scan the color table for minimal distance to r,g,b = {0,0,0} */
  261.  
  262.      int i, j;
  263.      short best, dist;
  264.      short t0, t1;
  265.  
  266.      for ( i=0, best=0, dist=32000; i < usedColors; i++) 
  267.      {
  268.           j = distance( colorstats[i][0], 0 );
  269.           if ( j < dist) 
  270.           {
  271.                best = i;
  272.                dist = j;
  273.           }
  274.      }
  275.  
  276.      /* colorstats[0] gets darkest color for background */
  277.  
  278.      t0 = colorstats[ best ][ 0 ];
  279.      t1 = colorstats[ best ][ 1 ];
  280.      colorstats[ best ][ 0 ] = colorstats[ 0 ][ 0 ];  
  281.      colorstats[ best ][ 1 ] = colorstats[ 0 ][ 1 ];
  282.      colorstats[ 0 ][ 0 ] = t0;
  283.      colorstats[ 0 ][ 1 ] = t1;
  284.  
  285.  
  286. }
  287.  
  288. main(argc,argv)
  289. int        argc;
  290. char        **argv;
  291. {
  292.      short  i, j, k;
  293.      short  xRes, yRes;
  294.      short  gap;
  295.      short  t0, t1, prgb, crgb, cpix, ppix, maxdis;
  296.      char   *s;
  297.      char   errmsg[80];
  298.  
  299.  
  300.      printf(VERSION);
  301.  
  302.      fname[0] = '\0';
  303.  
  304.      for (i=1; i<argc; i++) 
  305.      {
  306.           if (*argv[i] == '-')
  307.           {
  308.                argv[i]++;
  309.  
  310.                if (toupper(*argv[i]) == 'G')
  311.                {    
  312.                     /* 
  313.                      *   the output filename may be part of the current
  314.                      *   argv, or may be the next, depending on exactly
  315.                      *   how the operator typed it.  
  316.                      */
  317.  
  318.                     giffile = TRUE;
  319.                     argv[i]++;
  320.                     if (*argv[i] == '\0')    /* name isn't here   */
  321.                          i++;                /* try the next argv */
  322.  
  323.                     if (i<argc)
  324.                     {
  325.                          /* 
  326.                           *   get the output filename, if present,
  327.                           *   leaving room for possible concatination
  328.                           *   of a filetype
  329.                           */
  330.                          strncpy( outname, argv[i], sizeof(outname)-5 );
  331.  
  332.                          /* if no filetype, default to .GIF */
  333.                          if ( strchr( outname, '.' ) == NULL )
  334.                               strcat( outname, ".GIF" );
  335.                     }
  336.                     else
  337.                          outname[0] = '\0';  /* no output filename */
  338.                }
  339.                else
  340.                {
  341.                     sprintf( errmsg, "unrecognized command line option: -%c",*argv[i]);
  342.                     usageExit( errmsg );
  343.                }
  344.           }
  345.           else
  346.           {          
  347.                if (numfiles > 9) 
  348.                     usageExit("too many input files supplied (9 max.)");
  349.  
  350.                strcpy( str, argv[i] );  /* filename into our temp buf */
  351.  
  352.                if ( strchr( str, '.' ) == NULL )  /* if no filetype */
  353.                     strcat( str, ".TMP" );        /* ..provide one  */
  354.  
  355.                ifil[numfiles].fp = open(str,O_RDONLY | O_BINARY,0);
  356.                if (ifil[numfiles].fp == -1)
  357.                {    
  358.                     printf("ERROR: Can't find input file '%s'.",str);
  359.                     continue;
  360.                }
  361.                else
  362.                {    /* 
  363.                      *   read and check the row, col spec 
  364.                      *   if not 320x200, bail out.
  365.                      */
  366.                     if ( read(ifil[numfiles].fp, (char *)&xRes, sizeof( short )) 
  367.                               != sizeof( short ) ||
  368.                          read(ifil[numfiles].fp, (char *)&yRes, sizeof( short )) 
  369.                               != sizeof( short )  )
  370.                     {
  371.                          printf("ERROR: Can't read file '%s' - ignored.\n",str);
  372.                          continue;
  373.                     }
  374.  
  375.                     if ( xRes != 320 || yRes != 200 )
  376.                     {
  377.                          printf("ERROR: %s is not a 320x200 MCGA data file - ignored\n",str);
  378.                          continue;
  379.                     }
  380.                }
  381.  
  382.                ifil[numfiles].curr = -9999;
  383.                numfiles++;
  384.           }
  385.      }
  386.  
  387.      if (numfiles == 0)
  388.           usageExit( "no valid input file(s) specified." );
  389.  
  390.      if ( giffile && outname[0] == '\0' )
  391.           usageExit( "no GIF output filename specified." );
  392.  
  393.      if (giffile)
  394.      {
  395.           /* check to see if output file exists */
  396.           ofil = open(outname, O_RDONLY);
  397.           close( ofil );
  398.  
  399.           if (ofil != -1)          /* yes, warn them */
  400.           {
  401.                printf("Output file \"%s\" exists.  Replace it (y/N)? ",outname);
  402.                if (toupper(getch()) != 'Y')
  403.                     exit( -1 );       /* no further message, just exit */
  404.           }
  405.      
  406.           /* now, open it for real... */
  407.           ofil = open(outname, O_WRONLY | O_BINARY | O_CREAT | O_TRUNC, 
  408.                                   S_IREAD | S_IWRITE );
  409.           if (ofil == -1) 
  410.                error( "can't create output file." );
  411.  
  412.           printf("\n");
  413.      }
  414.  
  415.      printf("Building a color histogram:\n");
  416.  
  417.      for (i = 0; i < TMPCOLORS; i++) 
  418.      {
  419.           colorstats[i][0] = i;
  420.           colorstats[i][1] = 0;
  421.      }
  422.  
  423.      /* read through the input file list, building the color table */
  424.      for (i = 0; i < MAXROW; i++ )
  425.           read_scanline(1,i);
  426.  
  427.      printf("\n");
  428.  
  429.      /* reset the input file list */
  430.      for (i = 0; i < numfiles; i++) 
  431.      {
  432.           lseek(ifil[i].fp,(long)(2*sizeof(int)),0);
  433.           ifil[i].curr = -9999;
  434.      }
  435.  
  436.      /*
  437.       *   we now sort the color table in descending order 
  438.       *   of quantity of pixels of each color
  439.       */
  440.  
  441.      for (gap = TMPCOLORS/2; gap > 0; gap /=2) 
  442.      {
  443.           for (i = gap; i < TMPCOLORS; i++) 
  444.           {
  445.                for (j = i-gap; 
  446.                      j >= 0 && colorstats[j][1] < colorstats[j+gap][1]; 
  447.                       j -= gap) 
  448.                {
  449.                     t0                  = colorstats[j][0];
  450.                     t1                  = colorstats[j][1];
  451.                     colorstats[j][0]    = colorstats[j+gap][0];
  452.                     colorstats[j][1]    = colorstats[j+gap][1];
  453.                     colorstats[j+gap][0]= t0;
  454.                     colorstats[j+gap][1]= t1;
  455.                }
  456.           }
  457.      }
  458.  
  459.      /* count colors with a population > 0 */
  460.      for (usedColors = 0 ; 
  461.                usedColors < TMPCOLORS && colorstats[usedColors][1] > 0; 
  462.                     usedColors++) 
  463.           ;
  464.  
  465. /* debug ----------------
  466.      printf("post-sort - Colors:population \n\t");
  467.      for (i = 0; i < usedColors; i++) 
  468.      {
  469.           printf("%03x:%05d ",colorstats[i][0],colorstats[i][1]);
  470.           if ((i % 7) == 7) 
  471.                printf("\n\t");
  472.      }
  473.      printf("Press any key to continue...");
  474.      while (!kbhit())
  475.           ;
  476.      getch();
  477. -------------- debug */
  478.  
  479.      if (usedColors == 0)
  480.      {
  481.           error( "\nInput file error, no color data." );
  482.      }
  483.      else if (usedColors < COLORS)
  484.      {
  485.           printf("\n%d colors used\n",usedColors);
  486.      }
  487.      else
  488.      {
  489.           printf("\nMapping %d colors into %d\n", usedColors, COLORS);
  490.  
  491.           for (maxdis = 2; maxdis < (TMPCOLORS/4); maxdis *= 2) 
  492.           {
  493.                for (i=usedColors/2; i < usedColors; i++) 
  494.                {
  495.                     for (j = 0; j < i; j++) 
  496.                     {
  497.                          if (distance(colorstats[i][0],colorstats[j][0]) < maxdis) 
  498.                          {
  499.                               /* delete colorstat[i][] */
  500.                               for (k=i+1; k<usedColors; k++) 
  501.                               {
  502.                                    colorstats[k-1][0] = colorstats[k][0];
  503.                                    colorstats[k-1][1] = colorstats[k][1];
  504.                               }
  505.                               --usedColors;
  506.                               --i;
  507.                               break;
  508.                          }
  509.                     }
  510.                     if (usedColors <= COLORS) break;
  511.                }
  512.                if (usedColors <= COLORS) break;
  513.           }
  514.      }
  515.  
  516.      /* set up to display the image */
  517.  
  518.      _setvideomode( _MRES256COLOR );    /* 320 x 200 x 256 color */
  519.  
  520.      /* now set up the palette      */
  521.  
  522.      getBackground();    /* force darkest color to colorstats[0] */
  523.  
  524.      for (i = 0; i < usedColors; i++) 
  525.      {    _remappalette( i, ((long)(colorstats[i][0] & 0x0F00) << 10) |
  526.                             ((long)(colorstats[i][0] & 0x00F0) << 6 ) |
  527.                             ((long)(colorstats[i][0] & 0x000F) << 2 ) );
  528.      }
  529.  
  530.      /* if a GIF file was requested, write the header here */
  531.  
  532.      if ( giffile && gifHdr())        /* GIF file is no good  */
  533.      {
  534.           exit( -1 );
  535.      }
  536.  
  537.     /* now figure out the pixels to display */
  538.  
  539.     cpix    = 0;
  540.     crgb    = colorstats[0][1];
  541.  
  542.     for (i = 0; i < MAXROW; i++) 
  543.     {
  544.      /* check if there was an attempt to abort */
  545.  
  546.           if (kbhit() && getch() == 0x1B)    /* ESC? */
  547.                error( "ABORT at operator request."); 
  548.                
  549.           if (read_scanline(2,i)) 
  550.           {
  551.                for (j = 0 ; j < MAXCOL; j++) 
  552.                {
  553.                     prgb = crgb;
  554.                     crgb = image[j];
  555.                     ppix = cpix;
  556.  
  557.                     if (j == 0)
  558.                          cpix = getcolor(ppix,&crgb,-1);
  559.                     else
  560.                          cpix = getcolor(ppix,&crgb,prgb);
  561.  
  562.                 /* display the computed pixel */
  563.  
  564.                     _setcolor( cpix );
  565.                     _setpixel( j, i );
  566.  
  567.                     if (giffile)             /* gif file? */
  568.                          if (gifPixel( cpix ))
  569.                          {
  570.                               exit( -1 );
  571.                          }     
  572.                }
  573.           }
  574.           else if (giffile)
  575.           {    
  576.                /* no line 'i' - write a dummy to the GIF output file */
  577.  
  578.                cpix = 0;      /* background */
  579.  
  580.                for (j = 0 ; j < MAXCOL; j++) 
  581.                     if (gifPixel( cpix ))
  582.                     {
  583.                          exit( -1 );
  584.                     }     
  585.           }
  586.      }
  587.      printf("\n");
  588.  
  589.      if (giffile)             /* gif file is complete */
  590.           gifClose();         /* wrap it up           */
  591.  
  592.      /* wait here until we get a Return key hit */
  593.      
  594.      putch( 0x07 );      /* go "beep"   */
  595.      while (1)
  596.           if (kbhit() && getch() == 0x0D)
  597.                break;
  598.  
  599.      /* complete, return display to normal text mode */
  600.  
  601.      _setvideomode( _DEFAULTMODE );
  602. }
  603.  
  604. /* get the next encoding for a pixel */
  605.  
  606. int getcolor(ppix,crgb,prgb)
  607. int ppix, *crgb, prgb;
  608. {
  609.      short i,j,val,cr,cg,cb,pr,pg,pb,nr,ng,nb,best,dist,nrgb;
  610.  
  611.      /* if same color, then return same as previous pixel */
  612.  
  613.      if (*crgb == prgb) 
  614.           return((int)ppix);
  615.  
  616.      /* set up for comparisons */
  617.  
  618.      cr = *crgb & (MAXGRAY-1);
  619.      cg = (*crgb >> BPP) & (MAXGRAY-1);
  620.      cb = (*crgb >> (BPP*2)) & (MAXGRAY-1);
  621.  
  622.      /* look for an exact match in the color table (or minimal distance) */
  623.  
  624.      for (i=0; i < usedColors; i++) 
  625.      {
  626.           if (colorstats[i][0] == *crgb) 
  627.                return (i);
  628.           if (i == 0) 
  629.           {
  630.                best = 0;
  631.                dist = distance(colorstats[i][0],*crgb);
  632.           }
  633.           else if ((j=distance(colorstats[i][0],*crgb)) < dist) 
  634.           {
  635.                best = i;
  636.                dist = j;
  637.           }
  638.      }
  639.  
  640.      /* do a best absolute */
  641.  
  642.      *crgb = colorstats[best][0];
  643.      return(best);
  644. }
  645.  
  646.  
  647. int distance(argb, brgb) 
  648. int argb, brgb;
  649. {
  650.      short b,g,r;
  651.  
  652.      /* set up for comparisons */
  653.  
  654.      r = argb & (MAXGRAY-1);
  655.      g = (argb >> BPP) & (MAXGRAY-1);
  656.      b = (argb >> (BPP*2)) & (MAXGRAY-1);
  657.  
  658.      r -= brgb & (MAXGRAY-1);
  659.      g -= (brgb >> BPP) & (MAXGRAY-1);
  660.      b -= (brgb >> (BPP*2)) & (MAXGRAY-1);
  661.  
  662.      return((int)(r*r + g*g + b*b));
  663. }
  664.